#if !PocketPC || Framework20
using System;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Security.Permissions;

namespace GeoFramework
{
#if PocketPC
    internal sealed class DynamicEventShutdownSignal
    {
        public DynamicEventShutdownSignal() { }

        ~DynamicEventShutdownSignal()
        {
            DynamicEvent.Dispose();
        }
    }
#endif

    /// <summary>Provides features for raising events using automatic thread marshaling.</summary>
    /// <remarks>
    /// 	<para>The task of raising an event can quickly become complicated in a
    ///     multithreaded environment. For example, if an event is handled within a Form, but
    ///     the event was raised from a separate thread from the form's own thread, the
    ///     <strong>Control.Invoke</strong> method must be used to marshal event code to the
    ///     form's thread to avoid application lock-ups. For large libraries such as this one
    ///     where there are numerous events, event code quickly becomes very complicated with
    ///     numerous <strong>Control.Invoke</strong> calls.</para>
    /// 	<para>This class attempts to completely eliminate the need to call
    ///     <strong>Control.Invoke</strong> by doing it automatically. when the Invoke or
    ///     BeginInvoke methods of this class are called, each delegate's target is examined to
    ///     see if it supports the <strong>ISynchronizeInvoke</strong> interface (or
    ///     <strong>Control</strong> class for the compact framework). If found, the target's
    ///     own <strong>Invoke</strong> method is called, marshalling the call to the form's
    ///     own thread. If necessary, Reflection is used to analyze the delegate's
    ///     target.</para>
    /// 	<para>Due to severe limitations of delegates in .NET Compact Framework 1.0, this
    ///     class is not available for Compact Framework 1.0 applications. However, this class
    ///     fully supports all other .NET platforms: .NET Frameworks 1.0 and 1.1, .NET Compact
    ///     Framework 2.0, and also the special "Deploy to My Computer" emulation environment
    ///     in Visual Studio.NET 2005. Developers which use a single code base for multiple
    ///     platforms can greatly benefit from this class.</para>
    /// </remarks>
    /// <example>
    ///     This example demonstrates how to use the <strong>DynamicEvent</strong> class to
    ///     invoke an event. The code remains the same regardless of which .NET platform is
    ///     used. 
    ///     <code lang="VB" title="[New Example]">
    /// Public Event MyEvent As EventHandler
    ///  
    /// Protected Overridable Sub OnMyEvent()
    ///     DynamicEvent.BeginInvoke(MyEventHandler, Me, EventArgs.Empty)
    /// End Sub
    ///     </code>
    /// 	<code lang="CS" title="[New Example]">
    /// public event EventHandler MyEvent;
    ///  
    /// protected virtual void OnMyEvent()
    /// {
    ///     DynamicEvent.BeginInvoke(MyEventHandler, this, EventArgs.Empty);
    /// }
    ///     </code>
    /// 	<code lang="VB" title="[New Example]" description="This example demonstrates how to support all .NET platforms, including Compact Framework 1.0, by using compiler directives.">
    /// Public Event MyEvent As EventHandler
    ///  
    /// Protected Overridable Sub OnMyEvent()
    ///     #If PocketPC And Not Framework20
    ///         RaiseEvent MyEventHandler(Me, EventArgs.Empty)
    ///     #Else    
    ///         DynamicEvent.BeginInvoke(MyEventHandler, Me, EventArgs.Empty)
    ///     #End If    
    /// End Sub
    ///     </code>
    /// 	<code lang="CS" title="[New Example]" description="This example demonstrates how to support all .NET platforms, including Compact Framework 1.0, by using compiler directives.">
    /// public event EventHandler MyEvent;
    ///  
    /// protected virtual void OnMyEvent()
    /// {
    ///     #if PocketPC &amp;&amp; !Framework20
    ///         if(MyEventHandler != null)
    ///             MyEventHandler(this, EventArgs.Empty);
    ///     #else
    ///         DynamicEvent.BeginInvoke(MyEventHandler, this, EventArgs.Empty);
    ///     #endif    
    /// }
    ///     </code>
    /// </example>
#if !PocketPC || DesignTime
#if Framework20
    [Obfuscation(Feature = "renaming", Exclude = false, ApplyToMembers = true)]
    [Obfuscation(Feature = "controlflow", Exclude = true, ApplyToMembers = true)]
    [Obfuscation(Feature = "stringencryption", Exclude = false, ApplyToMembers = true)]
#endif
    [ImmutableObject(true)]
#endif
    public 
#if Framework20
        static
#else
        sealed 
#endif
        class DynamicEvent
    {


#if PocketPC && Framework20
        private static PropertyInfo DeployToMyComputerTargetProperty = typeof(EventHandler).GetProperty("Target");
        private static FieldInfo DelegateTargetProperty = typeof(Delegate).GetField("_target", BindingFlags.NonPublic | BindingFlags.Instance);
#endif

#if VS2005Beta2
        private static PropertyInfo InvokeRequiredProperty = typeof(Control).GetProperty("InvokeRequired", BindingFlags.NonPublic | BindingFlags.Instance);
#endif
#if PocketPC
        private static Hashtable MethodCache = new Hashtable();
        private static Hashtable AsyncMethodCache = new Hashtable();
        private static Hashtable TargetCache = new Hashtable();
        private static Hashtable InvokeRequiredCache = new Hashtable();
        private static int pReflectionCacheSize = 200;
        private static DynamicEventShutdownSignal ShutdownSignal; 
#endif

#if PocketPC
        // Private class
        static DynamicEvent()
        {
            ShutdownSignal = new DynamicEventShutdownSignal();
        }

        internal static void Dispose()
        {
            // Clear out all hash tables to help the garbage collector finalize properly
            MethodCache.Clear();
            AsyncMethodCache.Clear();

#if PocketPC
                TargetCache.Clear();
                InvokeRequiredCache.Clear();
#endif

        }
#endif

#if PocketPC
        /// <summary>
        /// Controls the number of items cached during Reflection in order to improve performance.
        /// </summary>
        /// <remarks>Reflection must be used in some cases to examine event delegates and their targets.  Since Reflection can
        /// be expensive on the processor, a cache is used to bypass Reflected information.  This cache defaults to two hundred
        /// items in size.  If the cache expands past this size, the entire cache is emptied.
        /// </remarks>
        public static int ReflectionCacheSize
        {
            get
            {
                return pReflectionCacheSize;
            }
            set
            {
                if (pReflectionCacheSize < 1)
                    throw new ArgumentOutOfRangeException("The size of the Reflection cache must be at least one.  A value of at least 200 is recommended for the cache to be effective.");
                pReflectionCacheSize = value;
            }
        }
#endif

        /// <summary>
        /// Indicates if the specified delegate would be marshalled to the user interface
        /// thread if it were invoked.
        /// </summary>
        /// <remarks>
        /// 	<para>When a delegate is invoked using the <strong>DynamicEvent</strong> class,
        ///     this method is used to determine if the delegate should be marshalled to the user
        ///     interface thread, or whether it should be invoked normally. The target of the
        ///     delegate is analyzed to see if is supports <strong>ISynchronizeInvoke</strong> (or
        ///     <strong>Control</strong> on the Compact Framework). If so, the
        ///     <strong>InvokeRequired</strong> property is examined if it is available. If it
        ///     returns <strong>True</strong>, a value of <strong>True</strong> is returned. On the
        ///     Compact Framework, <strong>InvokeRequired</strong> does not exist, so
        ///     <strong>True</strong> is returned if the target is decended from
        ///     <strong>Control</strong>.</para>
        /// 	<para>This method is called automatically by this class and is provided only for
        ///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        ///     to invoke delegates.</para>
        /// </remarks>
        /// <returns>
        /// A <strong>Boolean</strong>, <strong>True</strong> if the delegate would be
        /// marshalled to the user interface thread if invoked.
        /// </returns>
        /// <param name="method">
        /// A <strong>Delegate</strong> to examine. Typically an
        /// <strong>EventHandler</strong> or custom event handler.
        /// </param>
        public static bool IsThreadMarshallingRequired(Delegate method)
        {
            if (method == null)
                throw new ArgumentNullException("method");

#if !PocketPC

            // Is it a synchronize invoke?
            ISynchronizeInvoke DelegateTarget = method.Target as ISynchronizeInvoke;
            return DelegateTarget != null && DelegateTarget.InvokeRequired;

#elif PocketPC && Framework20
            object InvokeRequired = InvokeRequiredCache[method];
            if (InvokeRequired == null)
            {
                Control Target = GetTarget(method) as Control;
                if (Target == null)
                {
                    InvokeRequired = false;
                    // Clear the cache if it's too big
                    if (InvokeRequiredCache.Count > pReflectionCacheSize)
                        InvokeRequiredCache.Clear();
                    // Cache the value
                    InvokeRequiredCache[method] = InvokeRequired;
                }
                else
                {
#if !VS2005Beta2
                    return Target.InvokeRequired;
#else 

                    if (Environment.OSVersion.Platform == PlatformID.WinCE)
                    {
                        /* In VS2005 beta 2, InvokeRequired is private.  In the RTM release, however,
                         * InvokeRequired is public (thank god).  Use Reflection to obtain the property
                         * value. 
                         */

                        // We're using the Beta 2 release of VS2005, so use reflection to get the value
                        return (bool)InvokeRequiredProperty.GetValue(Target, null);
                    }
                    else
                    {
                        // Deploy to My Computer has no way to access the "InvokeRequired" property
                        // so just return true;
                        InvokeRequired = true;
                        // Clear the cache if it's too big
                        if (InvokeRequiredCache.Count > pReflectionCacheSize)
                            InvokeRequiredCache.Clear();
                        // Cache the value
                        InvokeRequiredCache[method] = InvokeRequired;
                    }
#endif
                }
            }
            return (bool)InvokeRequired;
#endif
        }

        /// <summary>
        /// Indicates if the specified invocation list would be marshalled to the user
        /// interface thread if it were invoked.
        /// </summary>
        /// <remarks>
        /// 	<para>When a delegate is invoked using the <strong>DynamicEvent</strong> class,
        ///     this method is used to determine if the delegate should be marshalled to the user
        ///     interface thread, or whether it should be invoked normally. The targets of each
        ///     delegate in the array are analyzed to see if they support
        ///     <strong>ISynchronizeInvoke</strong> (or <strong>Control</strong> on the Compact
        ///     Framework). If so, the <strong>InvokeRequired</strong> property is examined if it
        ///     is available. If it returns <strong>True</strong>, a value of <strong>True</strong>
        ///     is returned. On the Compact Framework, <strong>InvokeRequired</strong> does not
        ///     exist, so <strong>True</strong> is returned if the target is decended from
        ///     <strong>Control</strong>.</para>
        /// 	<para>This method is called automatically by this class and is provided only for
        ///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        ///     to invoke delegates.</para>
        /// </remarks>
        /// <returns>
        /// A <strong>Boolean</strong>, <strong>True</strong> if at least one delegate in the
        /// array would be marshalled to the user interface thread if invoked.
        /// </returns>
        /// <param name="invocationList">
        /// An array of <strong>Delegate</strong> objects. Typically the output of
        /// <strong>Delegate.GetInvocationList()</strong>.
        /// </param>
        public static bool IsThreadMarshallingRequired(Delegate[] invocationList)
        {
#if !PocketPC
            // Is there only one target?
            if (invocationList.Length == 1)
            {
                // Is it a synchronize invoke?
                ISynchronizeInvoke DelegateTarget = invocationList[0].Target as ISynchronizeInvoke;
                return DelegateTarget != null && DelegateTarget.InvokeRequired;
            }
            else
            {
                foreach (Delegate d in invocationList)
                {
                    // Is it a synchronize invoke?
                    ISynchronizeInvoke DelegateTarget = d.Target as ISynchronizeInvoke;
                    if (DelegateTarget != null && DelegateTarget.InvokeRequired)
                        return true;
                }
                return false;
            }
#elif PocketPC && Framework20
            if (invocationList.Length == 1)
            {
                return IsThreadMarshallingRequired(invocationList[0]);
            }
            else
            {
                foreach (Delegate d in invocationList)
                {
                    if (IsThreadMarshallingRequired(d))
                        return true;
                }
                return false;
            }
#endif
        }

        /// <summary>Returns the objects containing event handlers for the specified delegate.</summary>
        /// <returns>
        /// An array of <strong>Objects</strong> representing the target for each delegate in
        /// the delegate's invocation list.
        /// </returns>
        /// <remarks>
        /// 	<para>This property examines the invocation list of a delegate in order to return
        ///     its targets. A "target" is an object which contains code for an event handler. On
        ///     Desktop Frameworks, the delegate's <strong>Target</strong> property is analyzed. On
        ///     Compact Framework 2.0, the "<strong>_target</strong>" property is private, so
        ///     reflection is used to obtain its value.</para>
        /// 	<para>This method is called automatically by this class and is provided only for
        ///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        ///     to invoke delegates.</para>
        /// </remarks>
        /// <param name="method">
        /// A <strong>Delegate</strong> to examine. Typically an
        /// <strong>EventHandler</strong> or custom event handler.
        /// </param>
        public static object[] GetTargets(Delegate method)
        {
            if (method == null)
                throw new ArgumentNullException("method");

            return GetTargets(method.GetInvocationList());
        }

        /// <remarks>
        /// 	<para>This property examines the invocation list of a delegate in order to return
        ///     its targets. A "target" is an object which contains code for an event handler. On
        ///     Desktop Frameworks, the delegate's <strong>Target</strong> property is analyzed. On
        ///     Compact Framework 2.0, the "<strong>_target</strong>" property is private, so
        ///     reflection is used to obtain its value.</para>
        /// 	<para>This method is called automatically by this class and is provided only for
        ///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        ///     to invoke delegates.</para>
        /// </remarks>
        /// <returns>
        /// An array of <strong>Objects</strong> representing the target for each delegate in
        /// the array.
        /// </returns>
        /// <summary>Returns the objects containing event handlers for the specified delegates.</summary>
        /// <param name="invocationList">
        /// An array of <strong>Delegate</strong> objects. Typically the output of
        /// <strong>Delegate.GetInvocationList()</strong>.
        /// </param>
        public static object[] GetTargets(Delegate[] invocationList)
        {
            if (invocationList == null)
                throw new ArgumentNullException("invocationList");

            // Make an array of results
            ArrayList Result = new ArrayList(invocationList.Length);
            // Add each delegate's target
            foreach (Delegate d in invocationList)
                Result.Add(GetTarget(d));
            // Return the list
            return (object[])Result.ToArray(typeof(object[]));
        }

        /// <summary>Returns a single target for the specified delegate.</summary>
        /// <remarks>
        /// 	<para>This property examines the invocation list of a delegate in order to return
        ///     its targets. A "target" is an object which contains code for an event handler. On
        ///     Desktop Frameworks, the delegate's <strong>Target</strong> property is analyzed. On
        ///     Compact Framework 2.0, the "<strong>_target</strong>" property is private, so
        ///     reflection is used to obtain its value.</para>
        /// 	<para>This method is called automatically by this class and is provided only for
        ///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        ///     to invoke delegates.</para>
        /// </remarks>
        /// <returns>An <strong>Object</strong> representing the target of the delegate.</returns>
        /// <param name="method">
        /// A <strong>Delegate</strong> to examine. Typically an
        /// <strong>EventHandler</strong> or custom event handler.
        /// </param>
        public static object GetTarget(Delegate method)
        {
            if (method == null)
                throw new ArgumentNullException("method");

#if !PocketPC
            return method.Target;
#elif PocketPC && Framework20
            // Are we using the Deploy to My Computer Feature?  
            object DelegateTarget = TargetCache[method];
            if (DelegateTarget == null)
            {
                if (Environment.OSVersion.Platform != PlatformID.WinCE)
                {
                    DelegateTarget = DeployToMyComputerTargetProperty.GetValue(method, null);
                }
                else
                {
                    DelegateTarget = DelegateTargetProperty.GetValue(method);
                }
                // Is the cache too huge now?  If so, expire it
                if (TargetCache.Count > pReflectionCacheSize)
                    TargetCache.Clear();
                // Set the new target
                TargetCache[method] = DelegateTarget;
            }
            return DelegateTarget;
#endif
        }

        /// <summary>Occurs when an unhandled exception is thrown by an event subscriber.</summary>
        /// <remarks>
        /// 	<para>When an event is raised, event subscribers are notified and begin executing
        ///     their own code. If an exception is raised within their code, the exception is
        ///     accidentally thrown back into the <strong>DynamicEvent</strong> class, where it
        ///     does not belong. The exception is channeled to this event, where the application
        ///     gets a chance to act upon the exception, then execution continues.</para>
        /// 	<para>Well-written applications which use <strong>Try...Catch</strong> blocks will
        ///     never need to trap this event. This event should be subscribed to during
        ///     development, however, to provide notification of any accidental exceptions.</para>
        /// </remarks>
        /// <example>
        ///     This example demonstrates how to use the <strong>ExceptionOccurred</strong> event
        ///     to be notified of unhandled exceptions within event handlers. Let's say you have an
        ///     event named " <strong>MyTestEvent</strong> " which gets invoked via
        ///     <strong>DynamicEvent.BeginInvoke</strong> . If the event subscriber for the event
        ///     raises an exception, the exception is caught and channeled to
        ///     <strong>DynamicEventExceptionOccurred</strong> , where it is then thrown. 
        ///     <code lang="VB" title="[New Example]">
        /// Dim MyTestEvent As EventHandler
        ///  
        /// Sub Main()
        ///     ' Receive notifications of event invocation errors
        ///     AddHandler DynamicEvent.ExceptionOccurred, DynamicEventExceptionOccurred
        ///     ' Subscribe to the test event
        ///     AddHandler MyTestEvent, MyTestEventOccurred
        ///     ' Invoke the test event
        ///     DynamicEvent.BeginInvoke(MyTestEvent, Me)
        /// End Sub
        ///  
        /// ' Occurs when an event subscriber causes an unhandled exception
        /// Public Sub DynamicEventExceptionOccurred(ByVal sender As Object, ByVal e As ExceptionEventArgs)
        ///     Throw e.Exception
        /// End Sub
        ///  
        /// Private Sub MyTestEventOccurred(ByVal sender As Object, ByVal e As EventArgs)
        ///     ' This line will cause an InvalidCastException to occur
        ///     Dim CauseProblem As Integer = CType(sender, Integer)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyTestEvent;
        ///  
        /// void Main()
        /// {
        ///     // Receive notifications of event invocation errors
        ///     DynamicEvent.ExceptionOccurred += new ExceptionEventHandler(DynamicEventExceptionOccurred);
        ///     // Subscribe to the test event
        ///     MyTestEvent += new EventHandler(MyTestEventOccurred);
        ///     // Invoke the test event
        ///     DynamicEvent.BeginInvoke(MyTestEvent, this);
        /// }
        ///  
        /// // Occurs when an event subscriber causes an unhandled exception
        /// public void DynamicEventExceptionOccurred(object sender, ExceptionEventArgs e)
        /// {
        ///     throw e.Exception;
        /// }
        ///  
        /// private void MyTestEventOccurred(object sender, EventArgs e)
        /// {
        ///     // This line will cause an InvalidCastException to occur
        ///     int CauseProblem = (int)sender;
        /// }
        ///     </code>
        /// </example>
        public static event ExceptionEventHandler ExceptionOccurred;

        /// <remarks>
        /// 	<para>This method executes the specified delegate synchronously using the specified
        ///     sender. If the event has no subscribers, this method returns and no exception is
        ///     thrown. If any of the delegate's targets implement
        ///     <strong>ISynchronizeInvoke</strong> (such as a <strong>Control</strong> or
        ///     <strong>Form</strong> object), the target's own <strong>Invoke</strong> method is
        ///     called to marshal the delegate to the user interface thread.</para>
        /// 	<para>If the delegate is an event, and it is not necessary to wait for the event to
        ///     complete, use the <strong>BeginInvoke</strong> method instead.</para>
        /// </remarks>
        /// <summary>Executes the specified delegate.</summary>
        /// <example>
        ///     This example uses the <strong>Invoke</strong> method to raise an event. Using
        ///     <strong>BeginInvoke</strong> is recommended instewad of <strong>Invoke</strong>
        ///     since it is typically not necessary to wait for an event to complete before
        ///     continuing.
        ///     <code lang="VB" title="[New Example]">
        /// Dim MyEvent As EventHandler
        ///  
        /// Sub Main()
        ///     DynamicEvent.Invoke(MyEvent)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyEvent;
        ///  
        /// void Main()
        /// {
        ///     DynamicEvent.Invoke(MyEvent);
        /// }
        ///     </code>
        /// </example>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        public static void Invoke(Delegate method)
        {
            // If there's no method, exit
            if (method == null)
                return;
            // Continue invocation
            InvokeInternal(method.GetInvocationList(), null, EventArgs.Empty);
        }

        /// <summary>Executes the specified delegate using the specified sender.</summary>
        /// <remarks>
        /// 	<para>This method executes the specified delegate synchronously using the specified
        ///     sender and no event arguments. If the event has no subscribers, this method returns
        ///     and no exception is thrown. If any of the delegate's targets implement
        ///     <strong>ISynchronizeInvoke</strong> (such as a <strong>Control</strong> or
        ///     <strong>Form</strong> object), the target's own <strong>Invoke</strong> method is
        ///     called to marshal the delegate to the user interface thread.</para>
        /// 	<para>If the delegate is an event and it is not necessary to wait for the event to
        ///     complete, use the <strong>BeginInvoke</strong> method instead.</para>
        /// </remarks>
        /// <example>
        ///     This example uses the <strong>Invoke</strong> method to raise an event. Using
        ///     <strong>BeginInvoke</strong> is recommended instewad of <strong>Invoke</strong>
        ///     since it is typically not necessary to wait for an event to complete before
        ///     continuing.
        ///     <code lang="VB" title="[New Example]">
        /// Dim MyEvent As EventHandler
        ///  
        /// Sub Main()
        ///     DynamicEvent.Invoke(MyEvent, Me)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyEvent;
        ///  
        /// void Main()
        /// {
        ///     DynamicEvent.Invoke(MyEvent, this);
        /// }
        ///     </code>
        /// </example>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        /// <param name="sender">
        /// An <strong>Object</strong> identifying the object which invoked the
        /// delegate.
        /// </param>
        public static void Invoke(Delegate method, object sender)
        {
            // If there's no method, exit
            if (method == null)
                return;
            // Continue invocation
            InvokeInternal(method.GetInvocationList(), sender, EventArgs.Empty);
        }

        /// <example>
        ///     This example demonstrates the preferred way to raise events using the
        ///     <strong>DynamicEvent</strong> class.
        ///     <code lang="VB" title="[New Example]">
        /// Dim MyEvent As EventHandler
        ///  
        /// Sub Main()
        ///     DynamicEvent.BeginInvoke(MyEvent)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyEvent;
        ///  
        /// void Main()
        /// {
        ///     DynamicEvent.BeginInvoke(MyEvent);
        /// }
        ///     </code>
        /// </example>
        /// <summary>Executes the specified delegate asynchronously.</summary>
        /// <returns>
        /// An <strong>IAsyncResult</strong> object if there is only one event subscriber,
        /// otherwise null.
        /// </returns>
        /// <remarks>
        /// 	<para>This method executes the specified delegate asynchronously (whenever
        ///     possible) using the specified sender. If the event has no subscribers, this method
        ///     returns null and no exception is thrown. If any of the delegate's targets implement
        ///     <strong>ISynchronizeInvoke</strong> (such as a <strong>Control</strong> or
        ///     <strong>Form</strong> object), the target's own <strong>BeginInvoke</strong> method
        ///     is called to marshal the delegate to the user interface thread.</para>
        /// 	<para>This method is the preferred way to invoke an event because it it typically
        ///     not necessary to wait for an event to complete before continuing execution.</para>
        /// 	<para>For Compact Framework 2.0, asynchronous delegates are not supported, so the
        ///     delegate is executed synchronously.</para>
        /// </remarks>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        /// <param name="sender">
        /// An <strong>Object</strong> identifying the object which invoked the
        /// delegate.
        /// </param>
        public static void BeginInvoke(Delegate method, object sender)
        {
            // If there's no method, exit
            if (method != null)
#if !PocketPC || Framework20
                // Use the ThreadPoll to call the delegate
            GeoFramework.Threading.ThreadPool.Queue(new WaitCallback(DoInvoke), new object[] { method.GetInvocationList(), sender, EventArgs.Empty });
#else
            // Continue invocation
            InvokeInternal(method.GetInvocationList(), sender, EventArgs.Empty);
#endif
        }

        /// <example>
        ///     This example demonstrates the preferred way to raise events using the
        ///     <strong>DynamicEvent</strong> class.
        ///     <code lang="VB" title="[New Example]">
        /// Dim MyEvent As EventHandler
        ///  
        /// Sub Main()
        ///     DynamicEvent.BeginInvoke(MyEvent, Me)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyEvent;
        ///  
        /// void Main()
        /// {
        ///     DynamicEvent.BeginInvoke(MyEvent, this);
        /// }
        ///     </code>
        /// </example>
        /// <summary>Executes the specified delegate asynchronously using the specified sender.</summary>
        /// <remarks>
        /// 	<para>This method executes the specified delegate asynchronously (whenever
        ///     possible) using the specified sender. If the event has no subscribers, this method
        ///     returns null and no exception is thrown. If any of the delegate's targets implement
        ///     <strong>ISynchronizeInvoke</strong> (such as a <strong>Control</strong> or
        ///     <strong>Form</strong> object), the target's own <strong>BeginInvoke</strong> method
        ///     is called to marshal the delegate to the user interface thread.</para>
        /// 	<para>This method is the preferred way to invoke an event because it it typically
        ///     not necessary to wait for an event to complete before continuing execution.</para>
        /// 	<para>For Compact Framework 2.0, asynchronous delegates are not supported, so the
        ///     delegate is executed synchronously.</para>
        /// </remarks>
        /// <returns>
        /// An <strong>IAsyncResult</strong> object if there is only one event subscriber,
        /// otherwise null.
        /// </returns>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        public static void BeginInvoke(Delegate method)
        {
            // If there's no method, exit
            if (method != null)
#if !PocketPC || Framework20
                // Use the ThreadPoll to call the delegate
            GeoFramework.Threading.ThreadPool.Queue(new WaitCallback(DoInvoke), new object[] { method.GetInvocationList(), null, EventArgs.Empty });
#else
            // Continue invocation
            InvokeInternal(method.GetInvocationList(), null, EventArgs.Empty);
#endif
        }

        /// <example>
        ///     This example demonstrates the preferred way to raise events using the
        ///     <strong>DynamicEvent</strong> class.
        ///     <code lang="VB" title="[New Example]">
        /// Dim MyEvent As EventHandler
        ///  
        /// Sub Main()
        ///     DynamicEvent.BeginInvoke(MyEvent, Me, EventArgs.Empty)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyEvent;
        ///  
        /// void Main()
        /// {
        ///     DynamicEvent.BeginInvoke(MyEvent, this, EventArgs.Empty);
        /// }
        ///     </code>
        /// </example>
        /// <summary>
        /// Executes the specified delegate asynchronously using the specified sender and
        /// event arguments.
        /// </summary>
        /// <remarks>
        /// 	<para>This method executes the specified delegate asynchronously (whenever
        ///     possible) using the specified sender. If the event has no subscribers, this method
        ///     returns null and no exception is thrown. If any of the delegate's targets implement
        ///     <strong>ISynchronizeInvoke</strong> (such as a <strong>Control</strong> or
        ///     <strong>Form</strong> object), the target's own <strong>BeginInvoke</strong> method
        ///     is called to marshal the delegate to the user interface thread.</para>
        /// 	<para>This method is the preferred way to invoke an event because it it typically
        ///     not necessary to wait for an event to complete before continuing execution.</para>
        /// 	<para>For Compact Framework 2.0, asynchronous delegates are not supported, so the
        ///     delegate is executed synchronously.</para>
        /// </remarks>
        /// <returns>
        /// An <strong>IAsyncResult</strong> object if there is only one event subscriber,
        /// otherwise null.
        /// </returns>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        /// <param name="sender">
        /// An <strong>Object</strong> identifying the object which invoked the
        /// delegate.
        /// </param>
        /// <param name="e">
        /// An <strong>EventArgs</strong> object containing any arguments involved with the
        /// event.
        /// </param>
        public static void BeginInvoke(Delegate method, object sender, EventArgs e)
        {
            // If there's no method, exit
            if (method != null)
#if !PocketPC || Framework20
                // Use the ThreadPool to call the delegate
                GeoFramework.Threading.ThreadPool.Queue(new WaitCallback(DoInvoke), new object[] { method.GetInvocationList(), sender, e });
#else
                // Continue invocation
                InvokeInternal(method.GetInvocationList(), sender, e);
#endif
    }

        /// <summary>
        /// Executes the specified delegate using the specified sender and event
        /// arguments.
        /// </summary>
        /// <remarks>
        /// 	<para>This method executes the specified delegate synchronously using the specified
        ///     sender and event arguments. If the event has no subscribers, this method returns
        ///     and no exception is thrown. If the delegate's target implements
        ///     <strong>ISynchronizeInvoke</strong>, such as a <strong>Control</strong> or
        ///     <strong>Form</strong>, that object's own <strong>Invoke</strong> method is called
        ///     to marshal the delegate to the control's own thread.</para>
        /// 	<para>If the delegate is an event and it is not necessary to wait for the event to
        ///     complete, use the <strong>BeginInvoke</strong> method instead.</para>
        /// </remarks>
        /// <example>
        ///     This example uses the <strong>Invoke</strong> method to raise an event. Using
        ///     <strong>BeginInvoke</strong> is recommended instewad of <strong>Invoke</strong>
        ///     since it is typically not necessary to wait for an event to complete before
        ///     continuing.
        ///     <code lang="CS" title="[New Example]">
        /// Dim MyEvent As EventHandler
        ///  
        /// Sub Main()
        ///     DynamicEvent.Invoke(MyEvent, Me, EventArgs.Empty)
        /// End Sub
        ///     </code>
        /// 	<code lang="CS" title="[New Example]">
        /// EventHandler MyEvent;
        ///  
        /// void Main()
        /// {
        ///     DynamicEvent.Invoke(MyEvent, this, EventArgs.Empty);
        /// }
        ///     </code>
        /// </example>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        /// <param name="sender">
        /// An <strong>Object</strong> identifying the object which invoked the
        /// delegate.
        /// </param>
        /// <param name="e">
        /// An <strong>EventArgs</strong> object containing any arguments involved with the
        /// event.
        /// </param>
        public static void Invoke(Delegate method, object sender, EventArgs e)
        {
            // If there's no method, exit
            if (method == null)
                return;

            // Continue invocation
            InvokeInternal(method.GetInvocationList(), sender, e);
        }

        private static void DoInvoke(object state)
        {
            /* This method is called via the ThreadPool.  This
             * simply calls InvokeInternal like a regular invoke,
             * but, thanks to the ThreadPool, allows us to simulate
             * a "BeginInvoke" call.
             */

            object[] Parameters = (object[])state;
            Delegate[] invocationList = (Delegate[])Parameters[0];
            object sender = Parameters[1];
            EventArgs e = (EventArgs)Parameters[2];

            // Now call as usual
            if(invocationList != null)
                InvokeInternal(invocationList, sender, e);
        }

        private static void InvokeInternal(Delegate[] invocationList, object sender, EventArgs e)
        {
            // Examine each delegate to see if it must be marshalled
            foreach (Delegate d in invocationList)
            {
                try
                {
                    if (IsThreadMarshallingRequired(d))
                    {
                        MarshalledInvokeInternal(d, new object[] { sender, e });
                    }
                    else
                    {
                        UnmarshalledInvokeInternal(d, new object[] { sender, e });
                    }
                }
#if !PocketPC || Framework20
                catch (ThreadAbortException)
                {
                    break;
                }
#endif
                catch
                {
                    // Exceptions must not prevent the remaining invocation list from executing!
                    continue;
                }
            }
        }

        ///// <summary>
        ///// Invokes the specified delegate after marshalling it to the user interface
        ///// thread.
        ///// </summary>
        ///// <remarks>
        ///// 	<para>This method will attempt to marshal a delegate to the user interface thread
        /////     via the delegate's target <strong>Invoke</strong> method, even if thread
        /////     marshalling is not necessary.</para>
        ///// 	<para>This method is called automatically by this class and is provided only for
        /////     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        /////     to invoke delegates.</para>
        ///// </remarks>
        ///// <param name="method">
        ///// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        ///// or custom event handler.
        ///// </param>
        //private static void MarshalledInvoke(Delegate method)
        //{
        //    MarshalledInvokeInternal(method, new object[] { null, EventArgs.Empty });
        //}

        ///// <summary>
        ///// Invokes the specified delegate after marshalling it to the user interface
        ///// thread.
        ///// </summary>
        ///// <remarks>
        ///// 	<para>This method will attempt to marshal a delegate to the user interface thread
        /////     via the delegate's target <strong>Invoke</strong> method, even if thread
        /////     marshalling is not necessary.</para>
        ///// 	<para>This method is called automatically by this class and is provided only for
        /////     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        /////     to invoke delegates.</para>
        ///// </remarks>
        ///// <param name="method">
        ///// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        ///// or custom event handler.
        ///// </param>
        ///// <param name="sender">
        ///// An <strong>Object</strong> identifying the object which invoked the
        ///// delegate.
        ///// </param>
        //private static void MarshalledInvoke(Delegate method, object sender)
        //{
        //    MarshalledInvokeInternal(method, new object[] { sender, EventArgs.Empty });
        //}

        ///// <summary>
        ///// Invokes the specified delegate after marshalling it to the user interface
        ///// thread.
        ///// </summary>
        ///// <remarks>
        ///// 	<para>This method will attempt to marshal a delegate to the user interface thread
        /////     via the delegate's target <strong>Invoke</strong> method, even if thread
        /////     marshalling is not necessary.</para>
        ///// 	<para>This method is called automatically by this class and is provided only for
        /////     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        /////     to invoke delegates.</para>
        ///// </remarks>
        ///// <param name="method">
        ///// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        ///// or custom event handler.
        ///// </param>
        ///// <param name="sender">
        ///// An <strong>Object</strong> identifying the object which invoked the
        ///// delegate.
        ///// </param>
        ///// <param name="e">
        ///// An <strong>EventArgs</strong> object containing any arguments involved with the
        ///// event.
        ///// </param>
        //private static void MarshalledInvoke(Delegate method, object sender, EventArgs e)
        //{
        //    MarshalledInvokeInternal(method, new object[] { sender, e });
        //}

        /// <summary>Marshals the specified delegate to the user interface thread.</summary>
        private static void MarshalledInvokeInternal(Delegate method, object[] parameters)
        {
            try
            {
#if !PocketPC
				// Use the Invoke method to marshal the delegate to the UI thread
                if(!((Control)method.Target).IsDisposed)
				    ((ISynchronizeInvoke)method.Target).Invoke(method, parameters);
#elif PocketPC && Framework20
                // Get the invocation target
                if(IsThreadMarshallingRequired(method))
                    // Invoke the event
                    ((Control)GetTarget(method)).Invoke(method, parameters);
#endif
            }
            catch (ObjectDisposedException)
            {
                // Ignore!
                return;
            }
            catch (ThreadAbortException)
            {
                // Ignore!
                return;
            }
            catch (InvalidOperationException)
            {
                try
                {
                    UnmarshalledInvoke(method, parameters);
                }
                catch (Exception ex)
                {
                    try
                    {
                        if (ExceptionOccurred != null)
                            ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
                    }
                    catch
                    {
                        // Ignore.  No way to handle
                    }
                }
            }
            catch (Exception ex)
            {
                try
                {
                    if (ExceptionOccurred != null)
                        ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
                }
                catch
                {
                    // Ignore.  No way to handle
                }
            }
        }

//#if !(PocketPC && Framework20)
//		/// <summary>
//		/// Invokes the specified delegate asynchronously after marshalling it to the user
//		/// interface thread.
//		/// </summary>
//		/// <remarks>
//		/// 	<para>This method will attempt to marshal a delegate to the user interface thread
//		///     via the delegate's target <strong>BeginInvoke</strong> method, even if thread
//		///     marshalling is not necessary.</para>
//		/// 	<para>This method is called automatically by this class and is provided only for
//		///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
//		///     to invoke delegates.</para>
//		/// </remarks>
//		/// <param name="method">
//		/// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
//		/// or custom event handler.
//		/// </param>
//		public static IAsyncResult MarshalledBeginInvoke(Delegate method)
//		{
//			return MarshalledBeginInvokeInternal(method, new object[] { null, EventArgs.Empty });
//		}
//
//		/// <summary>
//		/// Invokes the specified delegate asynchronously after marshalling it to the user
//		/// interface thread.
//		/// </summary>
//		/// <remarks>
//		/// 	<para>This method will attempt to marshal a delegate to the user interface thread
//		///     via the delegate's target <strong>BeginInvoke</strong> method, even if thread
//		///     marshalling is not necessary.</para>
//		/// 	<para>This method is called automatically by this class and is provided only for
//		///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
//		///     to invoke delegates.</para>
//		/// </remarks>
//		/// <param name="method">
//		/// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
//		/// or custom event handler.
//		/// </param>
//		/// <param name="sender">
//		/// An <strong>Object</strong> identifying the object which invoked the
//		/// delegate.
//		/// </param>
//		public static IAsyncResult MarshalledBeginInvoke(Delegate method, object sender)
//		{
//			return MarshalledBeginInvokeInternal(method, new object[] { sender, EventArgs.Empty });
//		}
//
//		/// <summary>
//		/// Invokes the specified delegate asynchronously after marshalling it to the user
//		/// interface thread.
//		/// </summary>
//		/// <remarks>
//		/// 	<para>This method will attempt to marshal a delegate to the user interface thread
//		///     via the delegate's target <strong>BeginInvoke</strong> method, even if thread
//		///     marshalling is not necessary.</para>
//		/// 	<para>This method is called automatically by this class and is provided only for
//		///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
//		///     to invoke delegates.</para>
//		/// </remarks>
//		/// <param name="method">
//		/// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
//		/// or custom event handler.
//		/// </param>
//		/// <param name="sender">
//		/// An <strong>Object</strong> identifying the object which invoked the
//		/// delegate.
//		/// </param>
//		/// <param name="e">
//		/// An <strong>EventArgs</strong> object containing any arguments involved with the
//		/// event.
//		/// </param>
//		public static IAsyncResult MarshalledBeginInvoke(Delegate method, object sender, EventArgs e)
//		{
//			return MarshalledBeginInvokeInternal(method, new object[] { sender, e });
//		}
//
//        private static IAsyncResult MarshalledBeginInvokeInternal(Delegate method, object[] parameters)
//        {
//			try
//			{
//#if !PocketPC
//				// Use the beginInvoke method to marshal the delegate to the UI thread
//				return ((ISynchronizeInvoke)method.Target).BeginInvoke(method, parameters);
//#elif PocketPC && Framework20
//                // Get the invocation target
//                Control Target = GetTarget(method) as Control;
//                return Target.BeginInvoke(method, parameters);
//#endif
//			}
//			catch (ObjectDisposedException)
//			{
//				// The target is gone!  Skip this delegate
//				return null;
//			}
//			catch (InvalidOperationException)
//			{
//				try
//				{
//					UnmarshalledInvoke(method, parameters);
//					return null;
//				}
//				catch (Exception ex)
//				{
//					try
//					{
//						if (ExceptionOccurred != null)
//							ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
//						return null;
//					}
//					catch
//					{
//						// Ignore.  No way to handle
//						return null;
//					}
//				}
//			}
//			catch (ThreadAbortException)
//			{
//				// Ignore!
//				return null;
//			}
//			catch (Exception ex)
//			{
//				try
//				{
//					if (ExceptionOccurred != null)
//						ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
//					return null;
//				}
//				catch
//				{
//					// Ignore.  No way to handle
//					return null;
//				}
//			}
//        }
//#endif

        ///// <summary>Invokes the specified delegate without using thread marshalling.</summary>
        ///// <remarks>
        ///// 	<para>This method will invoke a delegate normally, even if thread marshalling is
        /////     necessary.</para>
        ///// 	<para>This method is called automatically by this class and is provided only for
        /////     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        /////     to invoke delegates.</para>
        ///// </remarks>
        ///// <param name="method">
        ///// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        ///// or custom event handler.
        ///// </param>
        //private static void UnmarshalledInvoke(Delegate method)
        //{
        //    UnmarshalledInvokeInternal(method, new object[] { null, EventArgs.Empty });
        //}

        /// <summary>Invokes the specified delegate without using thread marshalling.</summary>
        /// <remarks>
        /// 	<para>This method will invoke a delegate normally, even if thread marshalling is
        ///     necessary.</para>
        /// 	<para>This method is called automatically by this class and is provided only for
        ///     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        ///     to invoke delegates.</para>
        /// </remarks>
        /// <param name="method">
        /// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        /// or custom event handler.
        /// </param>
        /// <param name="sender">
        /// An <strong>Object</strong> identifying the object which invoked the
        /// delegate.
        /// </param>
        private static void UnmarshalledInvoke(Delegate method, object sender)
        {
            UnmarshalledInvokeInternal(method, new object[] { sender, EventArgs.Empty });
        }

        ///// <summary>Invokes the specified delegate without using thread marshalling.</summary>
        ///// <remarks>
        ///// 	<para>This method will invoke a delegate normally, even if thread marshalling is
        /////     necessary.</para>
        ///// 	<para>This method is called automatically by this class and is provided only for
        /////     informational purposes. Use <strong>Invoke</strong> or <strong>BeginInvoke</strong>
        /////     to invoke delegates.</para>
        ///// </remarks>
        ///// <param name="method">
        ///// A <strong>Delegate</strong> to invoke. Typically an <strong>EventHandler</strong>
        ///// or custom event handler.
        ///// </param>
        ///// <param name="sender">
        ///// An <strong>Object</strong> identifying the object which invoked the
        ///// delegate.
        ///// </param>
        ///// <param name="e">
        ///// An <strong>EventArgs</strong> object containing any arguments involved with the
        ///// event.
        ///// </param>
        //private static void UnmarshalledInvoke(Delegate method, object sender, EventArgs e)
        //{
        //    UnmarshalledInvokeInternal(method, new object[] { sender, e });
        //}


//        private static void UnmarshalledBeginInvoke(Delegate method)
//        {
//            UnmarshalledBeginInvokeInternal(method, new object[] { null, EventArgs.Empty });
//        }

//        private static void UnmarshalledBeginInvoke(Delegate method, object sender)
//        {
//            UnmarshalledBeginInvokeInternal(method, new object[] { sender, EventArgs.Empty });
//        }

//        private static void UnmarshalledBeginInvoke(Delegate method, object sender, EventArgs e)
//        {
//            UnmarshalledBeginInvokeInternal(method, new object[] { sender, e });
//        }

//        private static void UnmarshalledBeginInvokeInternal(Delegate method, object[] parameters)
//        {
//#if PocketPC && Framework20
//            MethodInfo InvokeMethod = null;
//#endif

//            try
//            {
//#if !PocketPC
//                // Invoke the delegate regularly
//                method.DynamicInvoke(parameters);
//#elif PocketPC && Framework20

//                // Invoke the delegate using reflection
//                InvokeMethod = AsyncMethodCache[method] as MethodInfo;
//                if (InvokeMethod == null)
//                {
//                    InvokeMethod = method.GetType().GetMethod("Invoke");
//                    // Is the cache too huge now?  If so, expire it
//                    if (AsyncMethodCache.Count > pReflectionCacheSize)
//                        AsyncMethodCache.Clear();
//                    // Cache the new method
//                    AsyncMethodCache[method] = InvokeMethod;
//                }
//                // Queue the item on the thread pool
//                GeoFramework.Threading.ThreadPool.Queue(new WaitCallback(DoBeginInvoke), new object[] { InvokeMethod, method, parameters[0], parameters[1] });
//                //InvokeMethod.Invoke(method, parameters);

//#endif
//            }
//            catch (ObjectDisposedException)
//            {
//                // Ignore!
//            }
//            //catch (InvalidProgramException)
//            //{
//            //    try
//            //    {                    
//            //        UnmarshalledInvokeInternal(method, new object[] { parameters[0], parameters[1] });
//            //    }
//            //    catch (Exception ex)
//            //    {
//            //        try
//            //        {
//            //            if (ExceptionOccurred != null)
//            //                ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
//            //        }
//            //        catch
//            //        {
//            //            // Ignore.  No way to handle
//            //        }
//            //    }
//            //}
//            catch (InvalidOperationException)
//            {
//                try
//                {
//                    UnmarshalledInvokeInternal(method, new object[] { parameters[0], parameters[1] });
//                }
//                catch (Exception ex)
//                {
//                    try
//                    {
//                        if (ExceptionOccurred != null)
//                            ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
//                    }
//                    catch
//                    {
//                        // Ignore.  No way to handle
//                    }
//                }
//            }
//#if !PocketPC
//            catch (TargetParameterCountException)
//            {
//                try
//                {
//                    method.DynamicInvoke(new object[] { parameters[0], parameters[1] });
//                }
//                catch (Exception ex)
//                {
//                    try
//                    {
//                        if (ExceptionOccurred != null)
//                            ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
//                    }
//                    catch
//                    {
//                        // Ignore.  No way to handle
//                    }
//                }
//            }
//#endif
//            catch (Exception ex)
//            {
//                try
//                {
//                    if (ExceptionOccurred != null)
//                        ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
//                }
//                catch
//                {
//                    // Ignore.  No way to handle
//                }
//            }
//        }

//#if PocketPC && Framework20
//        private static void DoBeginInvoke(object state)
//        {
//            object[] Parameters = null;
//            try
//            {
//                Parameters = (object[])state;
//                MethodInfo InvokeMethod = (MethodInfo)Parameters[0];
//                Delegate method = (Delegate)Parameters[1];
//                InvokeMethod.Invoke(method, new object[] { Parameters[2], Parameters[3] });
//            }
//            catch (Exception ex)
//            {
//                try
//                {
//                    if (ExceptionOccurred != null)
//                        ExceptionOccurred(Parameters[2], new ExceptionEventArgs(ex));
//                }
//                catch
//                {
//                    // Ignore.  No way to handle
//                }
//            }
//        }
//#endif

        private static void UnmarshalledInvokeInternal(Delegate method, object[] parameters)
        {
            try
            {
#if !PocketPC

                // Invoke the delegate regularly
                method.DynamicInvoke(parameters);

#elif PocketPC && Framework20
                // Invoke the delegate using reflection
                MethodInfo InvokeMethod = MethodCache[method] as MethodInfo;
                if (InvokeMethod == null)
                {
                    InvokeMethod = method.GetType().GetMethod("Invoke");
                    // Is the cache too huge now?  If so, expire it
                    if (MethodCache.Count > pReflectionCacheSize)
                        MethodCache.Clear();
                    // Cache the new method
                    MethodCache[method] = InvokeMethod;
                }
                InvokeMethod.Invoke(method, parameters);
#endif
            }
            catch (NotSupportedException)
            {
                // Control.Invoke is required!
                try
                {
                    MarshalledInvokeInternal(method, parameters);
                }
                catch
                {
                    throw;
                }
            }
            catch (ObjectDisposedException)
            {
                // Ignore!
                return;
            }
            catch (ThreadAbortException)
            {
                // Ignore!
                return;
            }
            catch (Exception ex)
            {
                try
                {
                    if (ExceptionOccurred != null)
                        ExceptionOccurred(parameters[0], new ExceptionEventArgs(ex));
                }
                catch
                {
                    // Ignore.  No way to handle
                }
            }
        }
    }
}
#endif